<template>
  <transition name="fade">
    <div
      class="hevue-imgpreview-wrap"
      id="hevue-imgpreview-wrap"
      v-if="visible"
      ref="heImg"
      @click.stop="clickMask"
      @pointerup="removeMove"
    >
      <div class="he-img-wrap">
        <div
          class="heimgfont hevue-img-status-icon rotate-animation"
          v-show="imgState === 1"
        >
          &#xe6b1;
        </div>
        <!-- <div class="heimgfont loading">&#xe6b1;</div> -->
        <img
          :src="imgurl"
          ref="heImView"
          @click.stop=""
          v-show="imgState === 2"
          class="he-img-view"
          :style="
            'transform: scale(' +
            imgScale +
            ') rotate(' +
            imgRotate +
            'deg);margin-top:' +
            imgTop +
            'px;margin-left:' +
            imgLeft +
            'px;' +
            maxWH
          "
          @pointerdown.stop="pointerdown"
        />
        <!-- 图片加载失败 -->
        <div
          class="heimgfont hevue-img-status-icon"
          v-show="imgState === 3"
        >
          &#xec0d;
        </div>
        <!-- 关闭按钮 -->
        <div
          class="heimgfont he-close-icon"
          @click.stop="close({ way: 'closeBtn' })"
          v-if="closeBtn"
        >
          &#xe608;
        </div>
        <!-- 左箭头 -->
        <div
          class="arrow arrow-left heimgfont"
          @click.stop="toogleImg(false, 'btn')"
          v-if="arrowBtn && multiple"
        >
          &#xe620;
        </div>
        <!-- 右箭头 -->
        <div
          class="arrow arrow-right heimgfont"
          @click.stop="toogleImg(true, 'btn')"
          v-if="arrowBtn && multiple"
        >
          &#xe60d;
        </div>
        <!-- 控制条 -->
        <div
          class="he-control-bar-wrap"
          v-if="controlBar"
        >
          <div
            class="he-control-bar"
            @click.stop
          >
            <!-- 缩小 -->
            <div
              class="he-control-btn heimgfont"
              @click.stop="scaleFunc(-0.15)"
            >
              &#xe65e;
            </div>
            <!-- 放大 -->
            <div
              class="he-control-btn heimgfont"
              @click.stop="scaleFunc(0.15)"
            >
              &#xe65d;
            </div>
            <!-- 复位 -->
            <div
              class="he-control-btn heimgfont"
              v-show="isFull"
              @click.stop="imgToggle"
            >
              &#xe698;
            </div>
            <!-- 复位 -->
            <div
              class="he-control-btn heimgfont"
              v-show="!isFull"
              @click.stop="imgToggle"
            >
              &#xe86b;
            </div>
            <!-- 左转 -->
            <div
              class="he-control-btn heimgfont"
              @click.stop="rotateFunc(-90)"
            >
              &#xe670;
            </div>
            <!-- 右转 -->
            <div
              class="he-control-btn heimgfont"
              @click.stop="rotateFunc(90)"
            >
              &#xe66f;
            </div>
            <!-- 下载 -->
            <!-- <div class="he-control-btn heimgfont" @click.stop="downloadIamge">
              &#xe694;
            </div> -->
          </div>
        </div>
        <!-- 页码指示器 -->
        <div
          class="he-control-num"
          v-if="controlBar && multiple"
        >
          {{ imgIndex + 1 }} / {{ imgList.length }}
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
export default {
  name: 'previewImage',
  data() {
    return {
      // imgWidth: 0,
      // imgHeight: 0,
      visible: false, // 插件显示，默认为false
      imgScale: 1,
      imgTop: 0,
      imgLeft: 0,
      imgRotate: 0,
      isFull: false,
      maxWH: 'max-width:100%;max-height:100%;',
      clientX: 0,
      clientY: 0,
      imgIndex: 0,
      canRun: true,
      imgurl: '',
      imgState: 1,
      mobileScale: 0, // 手指离开时图片的缩放比例
      // 以下内容为用户传入配置
      // show: true, // 插件显示，默认为false
      url: '', // 预览图片的地址
      nowImgIndex: 0,
      multiple: false,
      imgList: [],
      // 以下为可全局配置
      controlBar: true,
      closeBtn: true,
      arrowBtn: true,
      keyboard: false,
      clickMaskCLose: false, // 是否点击遮罩关闭，默认false
      closeFn: null, // 关闭回调函数
      changeFn: null, // 切换图片回调函数
      pointers: {}, // 记录鼠标指针
      startDistance: 0, //开始的距离
    };
  },
  mounted() {
    this.initImg();
  },
  watch: {
    url() {
      this.initImg();
    },
    visible: {
      handler(newV) {
        if (newV) {
          this.$nextTick(() => {
            let _dom = document.getElementById('hevue-imgpreview-wrap');
            _dom.onmousewheel = this.scrollFunc;
            // 火狐浏览器没有onmousewheel事件，用DOMMouseScroll代替(滚轮事件)
            document.body.addEventListener('DOMMouseScroll', this.scrollFunc);
            // 禁止火狐浏览器下拖拽图片的默认事件
            document.ondragstart = function () {
              return false;
            };
            // 判断是否多图
            if (this.multiple) {
              if (Array.isArray(this.imgList) && this.imgList.length > 0) {
                this.imgIndex = Number(this.nowImgIndex) || 0;
                // this.url = this.imgList[this.imgIndex]
                this.changeUrl(this.imgList[this.imgIndex], this.imgIndex);
              } else {
                // console.error("imgList 为空或格式不正确");
              }
            } else {
              this.changeUrl(this.url);
            }
            // 判断是否开启键盘事件
            if (this.keyboard) {
              document.addEventListener('keydown', this.keyHandleDebounce);
            }
          });
        }
      },
      immediate: true,
    },
  },
  methods: {
    show() {
      this.visible = true;
    },
    close(data) {
      this.initImg();
      // this.maxWH = "max-width:100%;max-height:100%;";
      // this.isFull = false;
      // 移除火狐浏览器下的鼠标滚动事件
      document.body.removeEventListener('DOMMouseScroll', this.scrollFunc);
      //恢复火狐及Safari浏览器下的图片拖拽
      document.ondragstart = null;
      // 移除键盘事件
      if (this.keyboard) {
        document.removeEventListener('keydown', this.keyHandleDebounce);
      }
      this.visible = false;
      this.closeFn && this.closeFn(data);
    },
    initImg() {
      this.mobileScale = 1;
      this.imgScale = 1;
      this.imgRotate = 0;
      this.imgTop = 0;
      this.imgLeft = 0;
    },
    /**
     * 切换图片
     * true 下一张
     * false 上一张
     */
    toogleImg(bool, way) {
      let fromIndex = this.imgIndex;
      if (bool) {
        this.imgIndex++;
        if (this.imgIndex > this.imgList.length - 1) {
          this.imgIndex = 0;
        }
      } else {
        this.imgIndex--;
        if (this.imgIndex < 0) {
          this.imgIndex = this.imgList.length - 1;
        }
      }
      this.changeFn &&
        this.changeFn({
          type: bool ? 'next' : 'prev',
          fromImgIndex: fromIndex,
          fromImgUrl: this.imgList[fromIndex],
          toImgIndex: this.imgIndex,
          toImgUrl: this.imgList[this.imgIndex],
          way,
        });
      // this.url = this.imgList[this.imgIndex]
      this.changeUrl(this.imgList[this.imgIndex], this.imgIndex);
    },
    // 改变图片地址
    /**
     * @description:
     * @param {String} url 要显示的图片的url
     * @param {Number} index 当前显示当图片下标，防止用户点击切换图片过快
     * @return {*}
     */
    changeUrl(url, index) {
      this.imgState = 1;
      let img = new Image();
      img.src = url;
      img.onload = () => {
        // 如果加载出来图片当下标不是当前显示图片当下标，则不予显示（用户点击过快当时候，会出现用户点到第三张了，此时第一张图片才加载完当情况）
        if (index != undefined && index == this.imgIndex) {
          this.imgState = 2;
          this.imgurl = url;
        } else if (index == undefined) {
          this.imgState = 2;
          this.imgurl = url;
        }
      };
      img.onerror = () => {
        if (index != undefined && index == this.imgIndex) {
          this.imgState = 3;
        } else if (index == undefined) {
          this.imgState = 3;
        }
      };
    },
    // 旋转图片
    rotateFunc(deg) {
      this.imgRotate += deg;
    },
    // 图片缩放
    scaleFunc(num, bool) {
      if (this.imgScale <= 0.2 && num < 0) return;
      if (bool) {
        this.imgScale = num;
      } else {
        this.imgScale += num;
      }
    },
    // 图片原尺寸切换
    imgToggle() {
      this.initImg();
      if (this.isFull) {
        this.maxWH = 'max-width:100%;max-height:100%;';
      } else {
        this.maxWH = '';
      }
      this.isFull = !this.isFull;
    },
    // 鼠标滚轮缩放
    scrollFunc(e) {
      e = e || window.event;
      // e.returnValue = false // ie
      // 火狐下没有wheelDelta，用detail代替，由于detail值的正负和wheelDelta相反，所以取反
      e.delta = e.wheelDelta || -e.detail;

      e.preventDefault();
      if (e.delta > 0) {
        //当滑轮向上滚动时
        this.scaleFunc(0.05);
      }
      if (e.delta < 0) {
        //当滑轮向下滚动时
        this.scaleFunc(-0.05);
      }
    },

    pointerdown(e) {
      e.preventDefault();
      e = e || window.event;
      this.pointers[e.pointerId] = { x: e.clientX, y: e.clientY };
      this.clientX = e.clientX;
      this.clientY = e.clientY;
      if (Object.keys(this.pointers).length >= 2) {
        this.mobileScale = this.imgScale;
        this.startDistance = this.getDistance(Object.values(this.pointers));
      }
      this.$refs.heImg.onpointermove = this.movePointerFunc;
    },

    movePointerFunc(e) {
      e.preventDefault();
      e = e || window.event;
      // 判断多指还是单指
      if (Object.keys(this.pointers).length >= 2) {
        this.pointers[e.pointerId] = { x: e.clientX, y: e.clientY };
        const currentDistance = this.getDistance(Object.values(this.pointers));
        const scale = currentDistance / this.startDistance;
        // 判断是否手指缩放过，如果缩放过，要在上次缩放的比例基础上进行缩放
        if (this.mobileScale) {
          if (scale > 1) {
            // 放大
            this.scaleFunc(scale + this.mobileScale - 1, true);
          } else {
            // 缩小
            this.scaleFunc(scale * this.mobileScale, true);
          }
        } else {
          this.scaleFunc(scale, true);
        }
      } else {
        const pointer = Object.values(this.pointers)[0];
        let movementX = e.clientX - pointer.x;
        let movementY = e.clientY - pointer.y;
        this.imgLeft += movementX * 2;
        this.imgTop += movementY * 2;
        this.pointers = { [e.pointerId]: { x: e.clientX, y: e.clientY } };
      }
    },

    // 移除拖动事件
    removeMove(e) {
      e.preventDefault();
      delete this.pointers[e.pointerId];
      if (Object.keys(this.pointers).length <= 0) {
        this.$refs.heImg.onpointermove = null;
      }
    },

    keyHandleDebounce(e) {
      if (this.canRun) {
        // 如果this.canRun为true证明当前可以执行函数
        this.keyHandle(e);
        this.canRun = false; // 执行函数后一段时间内不可再次执行
        setTimeout(() => {
          this.canRun = true; // 等到了我们设定的时间之后，把this.canRun改为true，可以再次执行函数
        }, 300);
      }
    },
    // 键盘事件
    keyHandle(e) {
      e = window.event || e;
      var key = e.keyCode || e.which || e.charCode;
      switch (key) {
        case 27: // esc
          this.close({ way: 'esc' });
          break;
        case 65: // a键-上一张
          if (this.multiple) {
            this.toogleImg(false, 'key-a');
          }
          break;
        case 68: // d键-下一张
          if (this.multiple) {
            this.toogleImg(true, 'key-d');
          }
          break;
        case 87: // w键-放大
          this.scaleFunc(0.15);
          break;
        case 83: // s键-缩小
          this.scaleFunc(-0.15);
          break;
        case 81: // q键-逆时针旋转
          this.rotateFunc(-90);
          break;
        case 69: // e键-顺时针旋转
          this.rotateFunc(90);
          break;
        case 82: // r键-复位键
          this.initImg();
          break;

        default:
          break;
      }
    },
    // 点击遮罩层
    clickMask() {
      if (this.clickMaskCLose) {
        this.close({ way: 'mask' });
      }
    },
    //缩放 勾股定理方法-求两点之间的距离
    getDistance([p1, p2]) {
      const x = p2.x - p1.x,
        y = p2.y - p1.y;
      return Math.sqrt(x * x + y * y);
    },
    /**
     * @description:
     * @param {String} imgsrc
     * @param {*} name
     * @return {*}
     */
    downloadIamge() {
      //下载图片地址和图片名
      let image = new Image();
      // 解决跨域 Canvas 污染问题
      image.setAttribute('crossOrigin', 'anonymous');
      image.onload = function () {
        let canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        let context = canvas.getContext('2d');
        context.drawImage(image, 0, 0, image.width, image.height);
        let url = canvas.toDataURL('image/png'); //得到图片的base64编码数据
        let a = document.createElement('a'); // 生成一个a元素
        let event = new MouseEvent('click'); // 创建一个单击事件
        a.download = 'photo' + +new Date(); // 设置图片名称
        a.href = url; // 将生成的URL设置为a.href属性
        a.dispatchEvent(event); // 触发a的单击事件
      };
      image.onerror = function (err) {
        console.log('图片信息不正确或图片服务器禁止访问');
        console.log(err);
      };
      if (this.multiple) {
        image.src = this.imgList[this.imgIndex];
      } else {
        image.src = this.url;
      }
    },
  },
};
</script>

<style scoped>
@import './iconfont/iconfont.css';
@import './css/default.css';
.he-img-view {
  touch-action: none;
}
</style>
